package org.scheduler4j.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

import org.scheduler4j.Configuration;

public final class DateUtil {

	private static final int THANSAND_SECOND_PER_DAY = 1000 * 60 * 60 * 24;

	public static Date today() {
		return new Date();
	}

	public static Date createDate(int year, int month, int day) {
		Calendar cal = Calendar.getInstance();
		cal.clear();
		cal.set(year, month - 1, day);
		return cal.getTime();
	}

	public static int getYear(Date date) {
		Calendar cal = getCalendar(date);
		cal.setTime(date);
		return cal.get(Calendar.YEAR);
	}

	public static int getMonth(Date date) {
		Calendar cal = getCalendar(date);
		cal.setTime(date);
		return cal.get(Calendar.MONTH) + 1;
	}

	public static int getDay(Date date) {
		Calendar cal = getCalendar(date);
		cal.setTime(date);
		return cal.get(Calendar.DAY_OF_MONTH);
	}

	public static boolean isWeekday(Date date) {
		Calendar cal = getCalendar(date);
		cal.setTime(date);
		int day = cal.get(Calendar.DAY_OF_WEEK);
		return day != Calendar.SATURDAY && day != Calendar.SUNDAY;
	}

	/**
	 * get previous Sunday.
	 * 
	 * @param date
	 *            the base date
	 * @return previous Sunday
	 */
	public static Date getNearestSundayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		int d = calendar.get(Calendar.DAY_OF_WEEK);
		int delta = 0;
		switch (d) {
		case Calendar.SUNDAY:
			delta = 0;
			break;
		case Calendar.SATURDAY:
			delta--;
		case Calendar.FRIDAY:
			delta--;
		case Calendar.THURSDAY:
			delta--;
		case Calendar.WEDNESDAY:
			delta--;
		case Calendar.TUESDAY:
			delta--;
		case Calendar.MONDAY:
			delta--;
		default:
		}
		calendar.add(Calendar.DAY_OF_MONTH, delta);
		return calendar.getTime();
	}

	/**
	 * get the previous Saturday, if given day is Saturday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Saturday
	 */
	public static Date getNearestSaturdayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return date;
		}
		calendar = getCalendar(getNearestSundayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous Friday, if given day is Friday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Friday
	 */
	public static Date getNearestFridayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) {
			return date;
		}
		calendar = getCalendar(getNearestSaturdayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous Thursday, if given day is Thursday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Thursday
	 */
	public static Date getNearestThursdayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
			return date;
		}
		calendar = getCalendar(getNearestFridayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous Wednesday, if given day is Wednesday, return the given
	 * day directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Wednesday
	 */
	public static Date getNearestWednesdayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY) {
			return date;
		}
		calendar = getCalendar(getNearestThursdayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous Tuesday, if given day is Tuesday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Tuesday
	 */
	public static Date getNearestTuesdayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY) {
			return date;
		}
		calendar = getCalendar(getNearestWednesdayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous Monday, if given day is Monday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous Monday
	 */
	public static Date getNearestMondayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.MONDAY) {
			return date;
		}
		calendar = getCalendar(getNearestTuesdayBefore(date));
		calendar.add(Calendar.DAY_OF_MONTH, -1);
		return calendar.getTime();
	}

	/**
	 * get the previous weekend, if given day is weekend, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous weekend
	 */
	public static Date getNearestWeekendBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY
				|| calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return date;
		}
		return getNearestSundayBefore(date);
	}

	/**
	 * get the previous weekend.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous weekend
	 */
	public static Date getPreviousWeekendDay(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			return beforeDays(date, 1);
		}
		return getNearestSundayBefore(date);
	}

	/**
	 * get the previous weekday, if given day is weekday, return the given day
	 * directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the previous weekday
	 */
	public static Date getNearestWeekdayBefore(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY
				|| calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return getNearestFridayBefore(date);
		}
		return date;
	}

	/**
	 * get the day before xx day of today.
	 * 
	 * @param date
	 *            the date to check
	 * @param days
	 *            days before
	 * @return the return date
	 */
	public static Date beforeDays(Date date, int days) {
		Calendar cal = getCalendar(date);
		cal.add(Calendar.DAY_OF_MONTH, -1 * days);
		return cal.getTime();
	}

	/**
	 * get the day before xx week day of today.
	 * 
	 * @param date
	 *            the date to check
	 * @param days
	 *            week day before
	 * @return the return date
	 */
	public static Date beforeWeekDays(Date date, int days) {
		Date previousFriday = getNearestFridayBefore(getDateWithoutTime(date));
		int weeks = days / 5;
		int deltaEnd = days % 5;
		Calendar cal = getCalendar(previousFriday);
		int deltaStart = dateDiff(previousFriday, date);
		cal.add(Calendar.DAY_OF_MONTH, 7 * weeks - deltaStart - deltaEnd);
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			cal.add(Calendar.DAY_OF_MONTH, -1);
		} else if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			cal.add(Calendar.DAY_OF_MONTH, -2);
		}
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get next Monday.
	 * 
	 * @param date
	 *            the base date
	 * @return next Monday
	 */
	public static Date getNearestMondayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		int d = calendar.get(Calendar.DAY_OF_WEEK);
		int delta = 0;
		switch (d) {
		case Calendar.MONDAY:
			delta = 0;
			break;
		case Calendar.TUESDAY:
			delta++;
		case Calendar.WEDNESDAY:
			delta++;
		case Calendar.THURSDAY:
			delta++;
		case Calendar.FRIDAY:
			delta++;
		case Calendar.SATURDAY:
			delta++;
		case Calendar.SUNDAY:
			delta++;
		default:
		}
		calendar.add(Calendar.DAY_OF_MONTH, delta);
		return calendar.getTime();
	}

	/**
	 * get the next Tuesday, if the given day is Tuesday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Tuesday
	 */
	public static Date getNearestTuesdayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.TUESDAY) {
			return date;
		}
		calendar = getCalendar(getNearestMondayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next Wednesday, if the given day is Wednesday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Wednesday
	 */
	public static Date getNearestWednesdayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.WEDNESDAY) {
			return date;
		}
		calendar = getCalendar(getNearestTuesdayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next Thursday, if the given day is Thursday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Thursday
	 */
	public static Date getNearestThursdayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.THURSDAY) {
			return date;
		}
		calendar = getCalendar(getNearestWednesdayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next Friday, if the given day is Friday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Friday
	 */
	public static Date getNearestFridayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.FRIDAY) {
			return date;
		}
		calendar = getCalendar(getNearestThursdayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next Saturday, if the given day is Saturday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Saturday
	 */
	public static Date getNearestSaturdayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return date;
		}
		calendar = getCalendar(getNearestFridayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next Sunday, if the given day is Sunday, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next Sunday
	 */
	public static Date getNearestSundayAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			return date;
		}
		calendar = getCalendar(getNearestSaturdayAfter(date));
		calendar.add(Calendar.DAY_OF_MONTH, 1);
		return calendar.getTime();
	}

	/**
	 * get the next weekend, if the given day is weekend, return directly.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next weekend
	 */
	public static Date getNearestWeekendAfter(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY
				|| calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return date;
		}
		return getNearestSaturdayAfter(date);
	}

	/**
	 * get the next weekend.
	 * 
	 * @param date
	 *            the date to check
	 * @return the next weekend
	 */
	public static Date getNextWeekendDay(Date date) {
		Calendar calendar = getCalendar(date);
		if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			return afterDays(date, 1);
		}
		return getNearestSaturdayAfter(date);
	}

	/**
	 * create Calendar object with given Date.
	 * 
	 * @param date
	 *            the Date to create
	 * @return the Calendar object created
	 */
	private static Calendar getCalendar(Date date) {
		Calendar calendar = Calendar.getInstance(Configuration.getLocale());
		calendar.setTime(date);
		return calendar;
	}

	/**
	 * get Date object without time .
	 * 
	 * @param date
	 *            date to fulfill
	 * @return date without time
	 */
	public static Date getDateWithoutTime(Date date) {
		Calendar calendar = getCalendar(date);
		Calendar calendar2 = getCalendar(new Date(0));

		calendar2.clear();
		calendar2.set(Calendar.YEAR, calendar.get(Calendar.YEAR));
		calendar2.set(Calendar.MONTH, calendar.get(Calendar.MONTH));
		calendar2.set(Calendar.DAY_OF_MONTH,
				calendar.get(Calendar.DAY_OF_MONTH));
		calendar2.set(Calendar.HOUR_OF_DAY, 0);
		calendar2.set(Calendar.MINUTE, 0);
		calendar2.set(Calendar.SECOND, 0);
		calendar2.set(Calendar.MILLISECOND, 0);
		return calendar2.getTime();
	}

	/**
	 * get the difference between 2 dates, negative if date1 after date2.
	 * 
	 * @param date1
	 *            first date
	 * @param date2
	 *            second date
	 * @return the result
	 */
	public static int dateDiff(Date date1, Date date2) {
		Date start = getDateWithoutTime(date1);
		Date end = getDateWithoutTime(date2);
		int diff = 0;
		diff = (int) (start.getTime() - end.getTime())
				/ THANSAND_SECOND_PER_DAY;
		return diff;
	}

	/**
	 * get the Date object after xx weekdays.
	 * 
	 * @param date
	 *            base date
	 * @param days
	 *            weekdays after
	 * @return the Date found
	 */
	public static Date afterWeekDays(Date date, int days) {
		Date nextMonday = getNearestMondayAfter(date);
		int weeks = days / 5;
		int deltaEnd = days % 5;
		Calendar cal = getCalendar(nextMonday);
		int deltaStart = dateDiff(nextMonday, date);
		deltaStart = deltaStart > 2 ? (deltaStart - 2) : (deltaStart > 0 ? 1
				: 0);
		cal.add(Calendar.DAY_OF_MONTH, 7 * weeks - deltaStart + deltaEnd);
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY) {
			cal.add(Calendar.DAY_OF_MONTH, -1);
		} else if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			cal.add(Calendar.DAY_OF_MONTH, -2);
		}
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get the date after xx weeks.
	 * 
	 * @param date
	 *            the date to check
	 * @param weeks
	 *            the weeks after
	 * @return the return date
	 */
	public static Date afterWeeks(Date date, int weeks) {
		Calendar cal = getCalendar(date);
		cal.add(Calendar.WEEK_OF_MONTH, weeks);
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get the Date object after xx days.
	 * 
	 * @param date
	 *            the base date
	 * @param days
	 *            days after
	 * @return the Date got
	 */
	public static Date afterDays(Date date, int days) {
		Calendar cal = getCalendar(date);
		cal.add(Calendar.DAY_OF_MONTH, days);
		return cal.getTime();
	}

	/**
	 * get the Date object after xx months.
	 * 
	 * @param date
	 *            the base date
	 * @param months
	 *            months after
	 * @return the Date got
	 */
	public static Date afterMonths(Date date, int months) {
		Calendar cal = getCalendar(date);
		cal.add(Calendar.MONTH, months);
		return cal.getTime();
	}

	/**
	 * get the Date object after xx years.
	 * 
	 * @param date
	 *            the base date
	 * @param years
	 *            years after
	 * @return the Date got
	 */
	public static Date afterYears(Date date, int years) {
		Calendar cal = getCalendar(date);
		cal.add(Calendar.YEAR, years);
		return cal.getTime();
	}

	/**
	 * get the first day of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first date of month
	 */
	public static Date firstDayOfMonth(int year, int month) {
		Calendar cal = getCalendar(new Date());
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month - 1);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get the first day of year.
	 * 
	 * @param year
	 * @return
	 */
	public static Date firstDayOfYear(int year) {
		Calendar cal = getCalendar(new Date());
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, Calendar.JANUARY);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		return getDateWithoutTime(cal.getTime());
	}

	public static Date lastDayOfYear(int year) {
		Calendar cal = getCalendar(new Date());
		cal.set(Calendar.YEAR, year + 1);
		cal.set(Calendar.MONTH, Calendar.JANUARY);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.add(Calendar.DAY_OF_MONTH, -1);
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get the last day of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last date of the month
	 */
	public static Date lastDayOfMonth(int year, int month) {
		Calendar cal = getCalendar(new Date());
		cal.set(Calendar.YEAR, year);
		cal.set(Calendar.MONTH, month);
		cal.set(Calendar.DAY_OF_MONTH, 1);
		cal.add(Calendar.DAY_OF_MONTH, -1);
		return getDateWithoutTime(cal.getTime());
	}

	/**
	 * get the first Monday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Monday of the month
	 */
	public static Date firstMondayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestMondayAfter(firstDay);
	}

	/**
	 * get the first Tuesday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Tuesday of the month
	 */
	public static Date firstTuesdayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestTuesdayAfter(firstDay);
	}

	/**
	 * get the first Wednesday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Wednesday of the month
	 */
	public static Date firstWednesdayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestWednesdayAfter(firstDay);
	}

	/**
	 * get the first Thursday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Thursday of the month
	 */
	public static Date firstThursdayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestThursdayAfter(firstDay);
	}

	/**
	 * get the first Friday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Friday of the month
	 */
	public static Date firstFridayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestFridayAfter(firstDay);
	}

	/**
	 * get the first Saturday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Saturday of the month
	 */
	public static Date firstSaturdayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestSaturdayAfter(firstDay);
	}

	/**
	 * get the first Sunday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first Sunday of the month
	 */
	public static Date firstSundayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		return getNearestSundayAfter(firstDay);
	}

	/**
	 * get the first weekday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first weekday of the month
	 */
	public static Date firstWeekDayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		Calendar cal = getCalendar(firstDay);
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
				|| cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			return getNearestMondayAfter(firstDay);
		}
		return firstDay;
	}

	/**
	 * get the first weekend day of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the first weekend day of the month
	 */
	public static Date firstWeekendDayOfMonth(int year, int month) {
		Date firstDay = firstDayOfMonth(year, month);
		Calendar cal = getCalendar(firstDay);
		if (cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY
				|| cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
			return firstDay;
		}
		return getNearestSaturdayAfter(firstDay);
	}

	/**
	 * get the last Monday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Monday of the month
	 */
	public static Date lastMondayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestMondayBefore(lastDay);
	}

	/**
	 * get the last Tuesday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Tuesday of the month
	 */
	public static Date lastTuesdayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestTuesdayBefore(lastDay);
	}

	/**
	 * get the last Wednesday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Wednesday of the month
	 */
	public static Date lastWednesdayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestWednesdayBefore(lastDay);
	}

	/**
	 * get the last Thursday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Thursday of the month
	 */
	public static Date lastThursdayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestThursdayBefore(lastDay);
	}

	/**
	 * get the last Friday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Friday of the month
	 */
	public static Date lastFridayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestFridayBefore(lastDay);
	}

	/**
	 * get the last Saturday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Saturday of the month
	 */
	public static Date lastSaturdayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestSaturdayBefore(lastDay);
	}

	/**
	 * get the last Sunday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last Sunday of the month
	 */
	public static Date lastSundayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestSundayBefore(lastDay);
	}

	/**
	 * get the last weekday of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last weekday of the month
	 */
	public static Date lastWeekDayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestWeekdayBefore(lastDay);
	}

	/**
	 * get the last weekend day of the month.
	 * 
	 * @param year
	 *            4 digit year
	 * @param month
	 *            month
	 * @return the last weekend day of the month
	 */
	public static Date lastWeekendDayOfMonth(int year, int month) {
		Date lastDay = lastDayOfMonth(year, month);
		return getNearestWeekendBefore(lastDay);
	}

	/**
	 * get day of the month.
	 * 
	 * @param date
	 *            the date to check
	 * @return the day in the month
	 */
	public static int getDayOfMonth(Date date) {
		Calendar cal = getCalendar(date);
		return cal.get(Calendar.DAY_OF_MONTH);
	}

	/**
	 * get the first day of week.
	 * 
	 * @param date
	 *            the day to check
	 * @return the first day of the week
	 */
	public static Date firstDayOfWeek(Date date) {
		return getNearestMondayBefore(date);
	}

	/**
	 * get day of week.
	 * 
	 * @param date
	 * @return
	 */
	public static int getDayOfWeek(Date date) {
		Calendar cal = getCalendar(date);
		return cal.get(Calendar.DAY_OF_WEEK);
	}

	/**
	 * get date from yyMMdd format string.
	 * 
	 * @param date
	 *            the formatted string.
	 * @return the date return.
	 */
	public static Date getDateByyyyyMMdd(String date) {
		try {
			return new SimpleDateFormat("yyyyMMdd").parse(date);
		} catch (ParseException e) {
			return null;
		}
	}
	
	public static int getWeekNo(Date date) {
		Calendar cal = getCalendar(date);
		return cal.get(Calendar.WEEK_OF_YEAR);
	}
}
